/*
 * Copyright 2009 Millibit Systems.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package jp.millibit.fiber
{
	import flash.events.Event;

	import jp.millibit.core.ObjectEvent;

	public class Task implements ITask
	{

		internal static function create(closure:Function):Task
		{
			return new FunctionTask(closure);
		}

		private var _task:ITask;

		public function Task(task:ITask = null)
		{
			_task = task;
		}

		internal function start(queue:CallbackQueue, exec:Execution, callback:Function):void
		{
			var fiber:Fiber = exec.fiber;
			var errorHandler:Function = function(e:ObjectEvent):void{
				notifyError(fiber, e.value);
				completeHandler(null);
			};
			var completeHandler:Function = function(e:Event):void{
				queue.setComplete();
				exec.dispatcher.removeEventListener(Execution.ERROR, errorHandler);
				exec.dispatcher.removeEventListener(Execution.CALLBACK, callbackHandler);
				exec.dispatcher.removeEventListener(Execution.COMPLETE, completeHandler);
				callback();
			};
			var callbackHandler:Function = function(e:ObjectEvent):void{
				queue.enqueue(e.value);
			};

			exec.dispatcher.addEventListener(Execution.ERROR, errorHandler);
			exec.dispatcher.addEventListener(Execution.CALLBACK, callbackHandler);
			exec.dispatcher.addEventListener(Execution.COMPLETE, completeHandler);

			try
			{
				run(exec);
			}
			catch (e:*)
			{
				notifyError(fiber, e);
				completeHandler(null);
			}
		}

		private function notifyError(fiber:Fiber, e:*):void
		{
			if (fiber === null)
			{
				return;
			}

			var errorHandler:Function = fiber.errorHandler;
			if (errorHandler === null)
			{
				notifyError(fiber.parent, e);
				return;
			}

			try
			{
				errorHandler(e);
			}
			catch (e:*)
			{
				notifyError(fiber.parent, e);
			}
		}

		public function run(exec:Execution):void
		{
			if (_task !== null)
			{
				_task.run(exec);
			}
		}
	}
}

import jp.millibit.fiber.Execution;
import jp.millibit.fiber.Task;

class FunctionTask extends Task
{

	private var _closure:Function;

	public function FunctionTask(closure:Function)
	{
		super(null);
		_closure = closure;
	}

	override public function run(exec:Execution):void
	{
		if (_closure.length === 0)
		{
			_closure();
			exec.complete();
		}
		else
		{
			_closure(exec);
		}
	}
}
